package com.jming.common;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.crypto.SecretKey;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;

/**
 *desc jwt配置类: JSON WEB TOKEN，分别由：Header（头部）、Payload（负载）、Signature（签名）组成
 * @author GrayPigeonHGH
 * @since 2024年03月16日
 */

public class JwtHelper {

    //设置解析令牌的密钥
    //依赖jjwt0.9.1之后的版本对于密钥安全性要求更高(体现在secret密钥的长度要达到一定的位数)
    private static SecretKey secretKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode("12345612qwwwwwwwwwwwwwwwwwwwwwwwwwwwww33333333333333333333333"));
    //或者 SecretKey secretKey = Keys.hmacShaKeyFor(s.getBytes());  //s为一个字符串秘钥（长度大于256位）

    private static long ttlMillis = 365 * 24 * 60 * 60 * 1000;

    /**
     * 生成token令牌（jwt）
     * 使用Hs256算法
     * @param claims     设置的信息
     * @return
     */
    public static String createToken(Map<String, Object> claims){

        String token = Jwts.builder()
                //设置签名使用的签名算法和签名使用的秘钥
                .signWith(secretKey, Jwts.SIG.HS256)
                .expiration(new Date(System.currentTimeMillis()+ttlMillis)) //设置token有效时长
                .claims(claims) //设置自定义负载信息
                .compact(); //设置过期时间
        return token;
    }

    /**
     * 先解析jwt
     * 再从Token中获取负载中的Claims：getPayload();
     * @param token token
     * @return 负载
     */
    private static Claims getPayload(String token)
    {
         return Jwts.parser()
                    .verifyWith(secretKey)
                    .build()
                    .parseSignedClaims(token)
                    .getPayload();
    }

    /**
     * 从Token中获取用户名
     * @param token token
     * @return String
     */
    public static String getUsername(String token){
        try
        {
            String userName = (String) getPayload(token).get("userName");
            return userName;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 从Token中获取用户ID
     * @param token token
     * @return Long
     */
    public static Long getUserId(String token){
        try
        {
            String userId = (String) getPayload(token).get("userId");
            return Long.valueOf(userId);
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 初始化负载内数据
     * @param userName 用户名
     * @return 负载集合
     */
    private static Map<String,Object> initClaims(String userName, String userId){
        Map<String, Object> claims = new HashMap<>();
        //"iss" (Issuer): 代表 JWT 的签发者。在这个字段中填入一个字符串，表示该 JWT 是由谁签发的。例如，可以填入你的应用程序的名称或标识符。
        claims.put("iss","jx");
        //"sub" (Subject): 代表 JWT 的主题，即该 JWT 所面向的用户。可以是用户的唯一标识符或者其他相关信息。
        claims.put("sub","hgh");
        //"exp" (Expiration Time): 代表 JWT 的过期时间。通常以 UNIX 时间戳表示，表示在这个时间之后该 JWT 将会过期。建议设定一个未来的时间点以保证 JWT 的有效性，比如一个小时、一天、一个月后的时间。
        claims.put("exp","");
        //"aud" (Audience): 代表 JWT 的接收者。这个字段可以填入该 JWT 预期的接收者，可以是单个用户、一组用户、或者某个服务。
        claims.put("aud","internal use");
        //"iat" (Issued At): 代表 JWT 的签发时间。同样使用 UNIX 时间戳表示。
        claims.put("iat",new Date());
        //"jti" (JWT ID): JWT 的唯一标识符。这个字段可以用来标识 JWT 的唯一性，避免重放攻击等问题。
        claims.put("jti", UUID.randomUUID().toString());
        //"nbf" (Not Before): 代表 JWT 的生效时间。在这个时间之前 JWT 不会生效，通常也是一个 UNIX 时间戳。我这里不填，没这个需求
        claims.put("nbf", "");
        claims.put("userId", userId);   //自定义负载
        claims.put("userName", userName);   //自定义负载
        return claims;
    }


    //测试
    public static void main(String[] args) {

        String token = JwtHelper.createToken(JwtHelper.initClaims("hgh", "2341513"));
        String userName = JwtHelper.getUsername(token);
        Long userId = JwtHelper.getUserId(token);
        System.out.println(token);
        System.out.println(userName);
        System.out.println(userId);

    }
}
